Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow validators to transform values #2786

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open

Conversation

sloria
Copy link
Member

@sloria sloria commented Jan 16, 2025

Still need to update the docs, but this proves the concept mentioned in #1391 (comment) , where we require that validators return a validated and possibly modified value, allowing users to apply a pipeline of transformations to any field

@sloria sloria requested a review from lafrech January 16, 2025 17:34
@sloria sloria added this to the 4.0 milestone Jan 16, 2025
Copy link
Member

@lafrech lafrech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this doesn't require many changes to existing validators because they already return the value.

It sounds a bit wrong to use a validator to modify the value, since it is not their intended use. That's not a strong argument, they could be called post_processors. It just makes me wonder if some day we'll realize that we took a shortcut that seemed fine but doesn't actually work for all cases.

Pydantic does it. But in a more complete way ("before", "after", "plain", "wrap"). The implementation in this PR is what Pydantic would call "after". What if tomorrow we want to implement "before", to modify the data before deserialization?

Are we trying to implement pre/post - load/dump but at field level rather than schema level? Should we do that instead?

@sloria
Copy link
Member Author

sloria commented Jan 16, 2025

fwiw sqlalchemy also allow validators to change the value: https://docs.sqlalchemy.org/en/20/orm/mapped_attributes.html#simple-validators

A quick way to add a “validation” routine to an attribute is to use the validates() decorator. An attribute validator can raise an exception, halting the process of mutating the attribute’s value, or can change the given value into something different.

i agree it isn't immediately apparent given the name "validators", but perhaps that's preferable than to adding more API surface? i'm not sure yet.

Are we trying to implement pre/post - load/dump but at field level rather than schema level? Should we do that instead?

that's an interesting idea. something like

class ArtistSchema(Schema):
    name = fields.Str(post_load=(strip_whitespace, uppercase))
    email = fields.Str(post_load=(strip_whitespace, uppercase))

# and/or

class ArtistSchema(Schema):
    name = fields.Str()
    email = fields.Str()

    @field_post_load("name", "email")
    def strip_whitespace(self, field_name: str, value: str) -> str:
        return value.strip()

i like this idea, but will have to give it some thought

@sloria
Copy link
Member Author

sloria commented Jan 16, 2025

i suppose one downside of that would be that validate/validates becomes somewhat redundant with post_load/field_post_load, right?

@sloria
Copy link
Member Author

sloria commented Jan 16, 2025

otoh, it's nice that field_pre/post_load/dump could be added as a non-breaking feature

@lafrech
Copy link
Member

lafrech commented Jan 16, 2025

i suppose one downside of that would be that validate/validates becomes somewhat redundant with post_load/field_post_load, right?

Possibly. But the call is not exactly the same since validate expects a validator, not a function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants